package com.jinwei.qunguanjia.web.system.controller;

import com.jinwei.qunguanjia.common.annotation.Log;
import com.jinwei.qunguanjia.common.constant.UserConstants;
import com.jinwei.qunguanjia.common.core.domain.Response;
import com.jinwei.qunguanjia.common.core.page.PageDataInfo;
import com.jinwei.qunguanjia.common.enums.BusinessTypeEnum;
import com.jinwei.qunguanjia.common.exception.GlobalExceptionHelper;
import com.jinwei.qunguanjia.common.utils.*;
import com.jinwei.qunguanjia.common.utils.bean.BeanValidators;
import com.jinwei.qunguanjia.common.utils.poi.ExcelUtil;
import com.jinwei.qunguanjia.system.dto.SysInitDTO;
import com.jinwei.qunguanjia.system.dto.SysRoleDTO;
import com.jinwei.qunguanjia.system.dto.SysUserDTO;
import com.jinwei.qunguanjia.system.service.SysConfigService;
import com.jinwei.qunguanjia.system.service.SysRoleService;
import com.jinwei.qunguanjia.system.service.SysUserService;
import com.jinwei.qunguanjia.system.utils.SecurityUtils;
import com.jinwei.qunguanjia.web.system.vo.SysInitVO;
import com.jinwei.qunguanjia.web.system.vo.SysUserVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Validator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户信息
 *
 * @author yuanzs
 */
@Slf4j
@RestController
@RequestMapping("/system/user")
public class SysUserController {

    @Resource
    private SysUserService sysUserService;

    @Resource
    private SysRoleService sysRoleService;

    @Resource
    private SysConfigService sysConfigService;

    @Resource
    protected Validator validator;

    /**
     * 新增用户
     * @param sysUserVO 对象
     */
    @PreAuthorize("@ss.hasPermission('system:user:save')")
    @Log(title = "用户管理-新增用户", businessType = BusinessTypeEnum.INSERT)
    @PostMapping("/save")
    public Response save(@Validated @RequestBody SysUserVO sysUserVO) throws IllegalAccessException {
        SysUserDTO sysUserDTO = new SysUserDTO();
        BeanUtils.copyProperties(sysUserVO, sysUserDTO);
        if (UserConstants.NOT_UNIQUE.equals(sysUserService.checkUserNameUnique(sysUserVO.getUserName()))) {
            return Response.fail("新增用户 "+sysUserVO.getUserName()+" 失败，登录账号已存在");
        } else if (StringUtils.isNotEmpty(sysUserVO.getPhoneNumber())
                && UserConstants.NOT_UNIQUE.equals(sysUserService.checkPhoneUnique(sysUserDTO))) {
            return Response.fail("新增用户 "+sysUserVO.getUserName()+" 失败，手机号码已存在");
        } else if (StringUtils.isNotEmpty(sysUserVO.getEmail())
                && UserConstants.NOT_UNIQUE.equals(sysUserService.checkEmailUnique(sysUserDTO))) {
            return Response.fail("新增用户 "+sysUserVO.getUserName()+" 失败，邮箱账号已存在");
        }
        sysUserDTO.setUserPassword(SecurityUtils.encryptPassword(sysUserVO.getUserPassword()));
        sysUserService.save(sysUserDTO);
        return Response.success();
    }

    /**
     * 修改用户
     * @param sysUserVO 对象
     */
    @PreAuthorize("@ss.hasPermission('system:user:update')")
    @Log(title = "用户管理-修改用户", businessType = BusinessTypeEnum.UPDATE)
    @PutMapping("/update")
    public Response update(@Validated @RequestBody SysUserVO sysUserVO) throws IllegalAccessException {
        sysUserService.checkUserAllowed(sysUserVO.getUserId());
        sysUserService.checkUserDataScope(sysUserVO.getUserId());
        SysUserDTO sysUserDTO = new SysUserDTO();
        BeanUtils.copyProperties(sysUserVO, sysUserDTO);
        if (StringUtils.isNotEmpty(sysUserVO.getPhoneNumber())
                && UserConstants.NOT_UNIQUE.equals(sysUserService.checkPhoneUnique(sysUserDTO))) {
            return Response.fail("修改用户 "+sysUserVO.getUserName()+" 失败，手机号码已存在");
        } else if (StringUtils.isNotEmpty(sysUserVO.getEmail())
                && UserConstants.NOT_UNIQUE.equals(sysUserService.checkEmailUnique(sysUserDTO))) {
            return Response.fail("修改用户 "+sysUserVO.getUserName()+" 失败，邮箱账号已存在");
        }
        sysUserService.update(sysUserDTO);
        return Response.success();
    }

    /**
     * 重置密码
     * @param sysUserVO 对象
     */
    @PreAuthorize("@ss.hasPermission('system:user:resetPwd')")
    @Log(title = "用户管理-重置密码", businessType = BusinessTypeEnum.UPDATE)
    @PutMapping("/resetPwd")
    public Response resetPwd(@RequestBody SysUserVO sysUserVO) {
        sysUserService.checkUserAllowed(sysUserVO.getUserId());
        sysUserService.checkUserDataScope(sysUserVO.getUserId());
        SysUserDTO sysUserDTO = new SysUserDTO();
        BeanUtils.copyProperties(sysUserVO, sysUserDTO);
        sysUserDTO.setUserPassword(SecurityUtils.encryptPassword(sysUserVO.getUserPassword()));
        sysUserService.update(sysUserDTO);
        return Response.success();
    }

    /**
     * 状态修改
     * @param sysUserVO 对象
     */
    @PreAuthorize("@ss.hasPermission('system:user:update')")
    @Log(title = "用户管理-状态修改", businessType = BusinessTypeEnum.UPDATE)
    @PutMapping("/changeStatus")
    public Response changeStatus(@RequestBody SysUserVO sysUserVO) {
        sysUserService.checkUserAllowed(sysUserVO.getUserId());
        sysUserService.checkUserDataScope(sysUserVO.getUserId());
        SysUserDTO sysUserDTO = new SysUserDTO();
        BeanUtils.copyProperties(sysUserVO, sysUserDTO);
        sysUserService.update(sysUserDTO);
        return Response.success();
    }

    /**
     * 获取用户列表
     */
    @PreAuthorize("@ss.hasPermission('system:user:list')")
    @GetMapping("/list")
    public PageDataInfo<SysUserVO> list(SysUserVO sysUserVO) {
        SysUserDTO sysUserDTO = new SysUserDTO();
        BeanUtils.copyProperties(sysUserVO, sysUserDTO);
        PageUtils.startPage();
        PageDataUtil<SysUserDTO, SysUserVO> pageDataUtil = new PageDataUtil<>();
        return pageDataUtil.transform(sysUserService.listPage(sysUserDTO), SysUserVO.class);
    }

    /**
     * 导出用户列表
     */
    @Log(title = "用户管理-导出", businessType = BusinessTypeEnum.EXPORT)
    @PreAuthorize("@ss.hasPermission('system:user:export')")
    @PostMapping("/export")
    public void export(HttpServletResponse response, SysUserVO sysUserVO) {
        SysUserDTO sysUserDTO = new SysUserDTO();
        BeanUtils.copyProperties(sysUserVO, sysUserDTO);
        ExcelUtil<SysUserVO> util = new ExcelUtil<>(SysUserVO.class);
        util.exportExcel(response, JsonUtils.copyList(sysUserService.listPage(sysUserDTO).getData(), SysUserVO.class), "用户数据");
    }

    /**
     * 导入用户列表
     */
    @Log(title = "用户管理-导入", businessType = BusinessTypeEnum.IMPORT)
    @PreAuthorize("@ss.hasPermission('system:user:import')")
    @PostMapping("/importData")
    public Response<String> importData(MultipartFile file, boolean updateSupport) throws Exception {
        ExcelUtil<SysUserVO> util = new ExcelUtil<>(SysUserVO.class);
        List<SysUserVO> userList = util.importExcel(file.getInputStream());
        if (StringUtils.isNull(userList) || userList.size() == 0) {
            throw GlobalExceptionHelper.localServiceException("导入用户数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        String password = sysConfigService.selectConfigByKey("sys.user.initPassword");
        for (SysUserVO user : userList) {
            try {
                // 验证是否存在这个用户
                SysUserDTO sysUserDTO = new SysUserDTO();
                sysUserDTO.setUserName(user.getUserName());
                SysUserDTO u = sysUserService.get(sysUserDTO);
                if (StringUtils.isNull(u)) {
                    BeanValidators.validateWithException(validator, user);
                    user.setUserPassword(SecurityUtils.encryptPassword(password));
                    BeanUtils.copyProperties(user, sysUserDTO);
                    sysUserService.save(sysUserDTO);
                    successNum++;
                    successMsg.append("<br/>").append(successNum).append("、账号 ").append(user.getUserName()).append(" 导入成功");
                } else if (updateSupport) {
                    BeanValidators.validateWithException(validator, user);
                    SysUserDTO updateUser = new SysUserDTO();
                    BeanUtils.copyProperties(user, updateUser);
                    updateUser.setUserId(u.getUserId());
                    sysUserService.update(updateUser);
                    successNum++;
                    successMsg.append("<br/>").append(successNum).append("、账号 ").append(user.getUserName()).append(" 更新成功");
                } else {
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、账号 ").append(user.getUserName()).append(" 已存在");
                }
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " 导入失败";
                failureMsg.append(msg).append(e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw GlobalExceptionHelper.localServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return Response.success(successMsg.toString());
    }

    /**
     * 下载导入模板
     */
    @PostMapping("/importTemplate")
    public void importTemplate(HttpServletResponse response) {
        ExcelUtil<SysUserVO> util = new ExcelUtil<>(SysUserVO.class);
        util.importTemplateExcel(response, "用户数据");
    }

    /**
     * 根据用户编号获取详细信息
     * @param userId 用户id
     */
    @PreAuthorize("@ss.hasPermission('system:user:query')")
    @GetMapping(value = { "/", "/{userId}" })
    public Response<SysUserVO> getInfo(@PathVariable(value = "userId", required = false) String userId) throws IllegalAccessException {
        sysUserService.checkUserDataScope(userId);
        List<SysRoleDTO> roles = sysRoleService.list(new SysRoleDTO());
        SysUserVO sysUserVO = new SysUserVO();
        sysUserVO.setRoles(SecurityUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !SecurityUtils.isRoleAdmin(r.getRoleId())).collect(Collectors.toList()));
        if (StringUtils.isNotNull(userId)) {
            SysUserDTO sysUser = sysUserService.getUserById(userId);
            sysUserVO = JsonUtils.parseObject(sysUser, SysUserVO.class);
            if (null != sysUser.getRoles()) {
                sysUserVO.setRoleIds(sysUser.getRoles().stream().map(SysRoleDTO::getRoleId).collect(Collectors.toList()));
            }
        }
        return Response.success(sysUserVO);
    }

    /**
     * 根据用户编号获取授权角色
     * @param userId 用户id
     */
    @PreAuthorize("@ss.hasPermission('system:user:query')")
    @GetMapping("/authRole/{userId}")
    public Response<SysUserVO> authRole(@PathVariable("userId") String userId) throws IllegalAccessException {
        SysUserVO sysUserVO = new SysUserVO();
        SysUserDTO user = sysUserService.getUserById(userId);
        List<SysRoleDTO> roles = sysRoleService.list(new SysRoleDTO());
        sysUserVO.setRoles(SecurityUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !SecurityUtils.isRoleAdmin(r.getRoleId())).collect(Collectors.toList()));
        sysUserVO = JsonUtils.parseObject(user, SysUserVO.class);
        return Response.success(sysUserVO);
    }

    /**
     * 用户授权角色
     * @param userId 用户id
     * @param roleIds 角色id列表
     */
    @PreAuthorize("@ss.hasPermission('system:user:update')")
    @Log(title = "用户管理-授权角色", businessType = BusinessTypeEnum.GRANT)
    @PutMapping("/authRole")
    public Response insertAuthRole(String userId, String[] roleIds) {
        sysUserService.checkUserDataScope(userId);
        sysUserService.saveUserAuth(userId, roleIds);
        return Response.success();
    }

    /**
     * 初始系统
     * @param sysInitVO 对象
     */
    @PostMapping("/init")
    public Response init(@Validated @RequestBody SysInitVO sysInitVO) {
        SysInitDTO sysInitDTO = new SysInitDTO();
        BeanUtils.copyProperties(sysInitVO, sysInitDTO);
        sysInitDTO.setAdminUserPassword(SecurityUtils.encryptPassword(sysInitVO.getAdminUserPassword()));
        sysUserService.init(sysInitDTO);
        return Response.success();
    }

}
